#include <iostream>
#include <thread>
#include "loghelper.h"
#include "processmanager.h"
#include "processhelper.hpp"
#include "utility.hpp"
#include "common.h"
using namespace RockLog;

ProcessManager::ProcessManager(AppConfig_t &cfg) :
    m_cfg(cfg)
{
}

ProcessManager::~ProcessManager()
{
}

void ProcessManager::init()
{
    for (auto i = 0; i < this->m_cfg.processNum; ++i)
    {
        std::string workerId = generateWorkerId(i);
        m_shmCheckers.push_back(std::move(SharedMemoryChecker(workerId, kSharedMemorySize)));
    }

    m_pids.resize(m_cfg.processNum);
    startCheckTimer();
}

void ProcessManager::startCheckTimer()
{
    LOG(kInfo) << "[startCheckTimer] start";
    std::thread([this]() {
        while (true)
        {
            Utility::sleep(this->m_cfg.checkProcessInterval);
            this->checkProcessStatus();
            LOG(kDebug) << "[startCheckTimer] checking...";
        }
    }).detach();
}

/*
启动：
将同名程序杀死-->启动程序-->加载配置文件
*/
bool ProcessManager::startWorkerProcess()
{
    {
        // 先删除子进程
        auto tup  = ProcessHelper::getAllProcessPidsByName(m_cfg.processName);
        auto pids = std::get<0>(tup);
        for (auto pid : pids)
            ProcessHelper::killProcess(pid);
    }
    {
        // 再删除非子进程
        auto tup  = ProcessHelper::getAllProcessPidsByName(m_cfg.processName);
        auto pids = std::get<0>(tup);
        for (auto pid : pids)
            ProcessHelper::killProcess(pid, false);
    }
    m_pids.clear();

    for (auto i = 0; i < m_cfg.processNum; i++)
    {
        std::string processArgv = std::to_string(i);
        auto newtup             = ProcessHelper::startProcess(m_cfg.processName, processArgv);
            m_pids.push_back(std::get<0>(newtup));
        if (m_pids[i] <= 0)
        {
            LOG(kErr) << "start process error: " << std::get<1>(newtup);
            return false;
        }
            Utility::usleep(1000);
    }
    return true;
}

void ProcessManager::checkProcessStatus()
{
    for (auto i = 0; i < m_cfg.processNum; i++)
    {
        if (-1 == ProcessHelper::isRunning(m_pids[i]))
        {
            LOG(kErr) << "process" << m_pids[i] << "is not running! start process"
                      << m_cfg.processName << "again.";
            startWorkerProcess();
        }

#ifdef BOOST_POSIX_API
        else if (-2 == ProcessHelper::isRunning(m_pids[i]))
        {
            LOG(kErr) << "process " << m_pids[i] << " is zombie!" << std::endl;
            if (waitpid(m_pids[i], NULL, 0) != m_pids[i])
            {
                LOG(kErr) << "terminate zombie process " << m_pids[i] << " failed!" << std::endl;
            }
            startWorkerProcess();
        }
#endif

        if (m_cfg.sharedMemoryCheck && -2 == m_shmCheckers[i].check())
        {
            LOG(kErr) << "process " << m_pids[i] << " sharedmeory check failed! start process "
                      << m_cfg.processName << " again.";
            startWorkerProcess();
        }
    }
}
